package com.kpmg.datalake.common.privilege;

import com.alibaba.fastjson.JSONObject;
import com.kpmg.datalake.common.enums.ResultCodeEnum;
import com.kpmg.datalake.common.service.RbacFunctionService;
import com.kpmg.datalake.common.utils.ContextHolderUtils;
import com.kpmg.datalake.common.vo.ServerResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

@Aspect
@Component
public class DataAuthAspect {

  private static final Logger logger = LoggerFactory.getLogger(DataAuthAspect.class);

  @Autowired
  private RbacFunctionService rbacFunctionService;

  @Pointcut("@annotation(com.kpmg.datalake.common.privilege.ValidateDataAuth)")
  public void validateDataAuth() {
  }

  @Before("validateDataAuth()")
  public void beforeValidateDataAuth(JoinPoint point) {
    HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder
        .getRequestAttributes()).getResponse();

    MethodSignature signature = (MethodSignature) point.getSignature();
    ValidateDataAuth validateDataAuth = signature.getMethod().getAnnotation(ValidateDataAuth.class);

    if (ContextHolderUtils.getLoginUser() == null) {
      responseResult(response);
      return;
    }
    String userId = ContextHolderUtils.getLoginUser().getUsrId();

    List<String> projectIdList = rbacFunctionService.queryProjectPrivilegeIdList(userId);

    String projectId = this
        .parseKey(validateDataAuth.key(), signature.getParameterNames(), point.getArgs());

    if (StringUtils.isEmpty(projectId) || !projectIdList.contains(projectId)) {
      logger.info("用户 [{}] 尝试访问数据，但无相应数据权限", userId);
      responseResult(response);
      return;
    }

  }

  private void responseResult(HttpServletResponse response) {
    try (OutputStream outputStream = response.getOutputStream()) {
      String outString = JSONObject.toJSONString(
          ServerResponse.serverResponse(ResultCodeEnum.CODE4010, null, null));
      outputStream.write(outString.getBytes());
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  /**
   * 获取缓存的key key 定义在注解上，支持SPEL表达式
   */
  private String parseKey(String key, String[] paraNameArr, Object[] args) {
    //使用SPEL进行key的解析
    ExpressionParser parser = new SpelExpressionParser();
    //SPEL上下文
    StandardEvaluationContext context = new StandardEvaluationContext();
    //把方法参数放入SPEL上下文中
    for (int i = 0; i < paraNameArr.length; i++) {
      context.setVariable(paraNameArr[i], args[i]);
    }
    return parser.parseExpression(key).getValue(context, String.class);
  }

}
